//
//  WXMediaEngine.m
//  SULoader
//
//  Created by tianlong on 2018/6/21.
//  Copyright © 2018年 万众科技. All rights reserved.
//

#import "WXMediaEngine.h"
#import "NSURL+WXMedia.h"
#import "NSString+WXMedia.h"
#import "WXMediaLog.h"

#import <UIKit/UIKit.h>
#import <AVFoundation/AVFoundation.h>
#import <MobileCoreServices/MobileCoreServices.h>

#define RequestTimeout 10.0

@interface WXMediaEngine ()<AVAssetResourceLoaderDelegate,NSURLSessionDelegate>
@property (nonatomic, strong) NSURL *url;
@property (nonatomic, strong) NSURLSession *session;
@property (nonatomic, strong) NSURLSessionDataTask *task;
@property (nonatomic, strong) AVPlayerItem *playItem;
@property (nonatomic, strong) AVAssetResourceLoadingRequest *loadingRequest;
//@property (nonatomic, strong) NSMutableArray *requestList;
@property (nonatomic, copy) NSString *MimeType;
@property (nonatomic, strong) NSURLResponse *response;
@property (nonatomic, strong) NSMutableData *mediaData;
@property (nonatomic, assign) long long fileLen; //文件长度
@end


@implementation WXMediaEngine

static NSString *kCacheScheme = @"__WXMedia__:";

#pragma mark - lazyload
- (NSMutableData *)mediaData {
    if(!_mediaData) {
        _mediaData = [NSMutableData data];
    }
    return _mediaData;
}

- (NSURLSession *)session {
    if (!_session) {
        NSURLSessionConfiguration *configuration = [NSURLSessionConfiguration defaultSessionConfiguration];
        NSOperationQueue *downloadQueue = [[NSOperationQueue alloc] init];
        NSURLSession *session = [NSURLSession sessionWithConfiguration:configuration delegate:self delegateQueue:downloadQueue];
        _session = session;
    }
    return _session;
}

#pragma mark - init方法
- (instancetype)initWithURL:(NSString *)url {
    self = [super init];
    if (self) {
        if (url.length > 0) {
            self.url = [NSURL URLWithString:url];
            self.fileLen = -1;
        }
    }
    return self;
}

#pragma mark - 开始加载
- (void)start {
    if (!self.url || self.url.absoluteString.length == 0) {
        [WXMediaLog logWithType:WXMediaLogTypeURLISEmpty label:WXMediaEngineJugeURL info:nil];
        return;
    }
    
    if (![self.url.absoluteString isValidUrl]) {
        [WXMediaLog logWithType:WXMediaLogTypeURLISInvalid label:WXMediaEngineJugeURL info:nil];
        return;
    }
    
    NSURL *assetURL = [self assetURLWithURL:self.url];
    AVURLAsset *urlAsset = [AVURLAsset URLAssetWithURL:assetURL options:nil];
    [urlAsset.resourceLoader setDelegate:self queue:dispatch_get_main_queue()];
    self.playItem = [AVPlayerItem playerItemWithAsset:urlAsset];
    if ([self.playItem respondsToSelector:@selector(setCanUseNetworkResourcesForLiveStreamingWhilePaused:)]) {
        self.playItem.canUseNetworkResourcesForLiveStreamingWhilePaused = YES;
    }
}

- (NSURL *)assetURLWithURL:(NSURL *)url {
    if (!url) {
        return nil;
    }
    
    NSURL *assetURL = [NSURL URLWithString:[kCacheScheme stringByAppendingString:[url absoluteString]]];
    return assetURL;
}

#pragma mark - 暂停
- (void)pause {
    [self.task cancel];
}

#pragma mark - 停止
- (void)stop {
    [self pause];
    self.task = nil;
}

#pragma mark - 将时间转成 mm:ss 的形式
- (NSString *)converTimeToString:(CGFloat)time {
    NSDate *date = [NSDate dateWithTimeIntervalSince1970:time];
    NSDateFormatter *formatter = [[NSDateFormatter alloc] init];
    if (time/3600 >= 1) {
        [formatter setDateFormat:@"HH:mm:ss"];
    } else {
        [formatter setDateFormat:@"mm:ss"];
    }
    NSString *timeStr = [formatter stringFromDate:date];
    return timeStr;
}

#pragma mark - AVAssetResourceLoaderDelegate
- (BOOL)resourceLoader:(AVAssetResourceLoader *)resourceLoader shouldWaitForLoadingOfRequestedResource:(AVAssetResourceLoadingRequest *)loadingRequest {
    self.loadingRequest = loadingRequest;
    NSURL *resourceURL = [loadingRequest.request URL];
    if ([resourceURL.absoluteString hasPrefix:kCacheScheme]) {
        [self startDownload:loadingRequest];
        return YES;
    }
    return NO;
}

- (void)startDownload:(AVAssetResourceLoadingRequest *)loadingRequest {
    NSURL *resourceURL = [loadingRequest.request URL];
    NSURL *originURL = nil;
    NSString *originStr = [resourceURL absoluteString];
    originStr = [originStr stringByReplacingOccurrencesOfString:kCacheScheme withString:@""];
    originURL = [NSURL URLWithString:originStr];
    
    long long offset = loadingRequest.dataRequest.requestedOffset;
    NSInteger length = loadingRequest.dataRequest.requestedLength;
    NSRange range = NSMakeRange((NSUInteger)offset, length);
    
    long long fromOffset = range.location;
    long long endOffset  = range.location + range.length - 1;
    
    NSMutableURLRequest *request = [NSMutableURLRequest requestWithURL:originURL];
    request.cachePolicy = NSURLRequestReloadIgnoringLocalAndRemoteCacheData;
    NSString *rangeStr = [NSString stringWithFormat:@"bytes=%lld-%lld", fromOffset, endOffset];
    [request setValue:rangeStr forHTTPHeaderField:@"Range"];
    //[request setValue:@"application/octet-stream" forHTTPHeaderField:@"Content-Type"];
    self.task = [self.session dataTaskWithRequest:request];
    [self.task resume];
}

- (void)resourceLoader:(AVAssetResourceLoader *)resourceLoader didCancelLoadingRequest:(AVAssetResourceLoadingRequest *)loadingRequest {
    NSLog(@"didCancelLoadingRequest");
}

#pragma mark - 日志
- (void)logWithRequeset:(AVAssetResourceLoadingRequest *)loadingRequest {
    NSLog(@"%s\nrequestOff      = %lld  \ncurrentOffset   = %lld,   \nrequestedLength = %ld",__FUNCTION__,loadingRequest.dataRequest.requestedOffset,loadingRequest.dataRequest.currentOffset,(long)loadingRequest.dataRequest.requestedLength);
}

#pragma mark - NSURLSessionDataDelegate
- (void)URLSession:(NSURLSession *)session didReceiveChallenge:(NSURLAuthenticationChallenge *)challenge completionHandler:(void (^)(NSURLSessionAuthChallengeDisposition, NSURLCredential * _Nullable))completionHandler {
    NSURLCredential *card = [[NSURLCredential alloc] initWithTrust:challenge.protectionSpace.serverTrust];
    completionHandler(NSURLSessionAuthChallengeUseCredential,card);
}
//服务器响应
- (void)URLSession:(NSURLSession *)session
          dataTask:(NSURLSessionDataTask *)dataTask didReceiveResponse:(NSURLResponse *)response
 completionHandler:(void (^)(NSURLSessionResponseDisposition))completionHandler {
    NSString *mimeType = response.MIMEType;
    
    if ([mimeType rangeOfString:@"video/"].location == NSNotFound &&
        [mimeType rangeOfString:@"audio/"].location == NSNotFound &&
        [mimeType rangeOfString:@"application"].location == NSNotFound) {
        NSLog(@"completionHandler(NSURLSessionResponseCancel)");
        completionHandler(NSURLSessionResponseCancel);
        return;
    }
    
    
    NSHTTPURLResponse * httpResponse = (NSHTTPURLResponse *)response;
    NSString * contentRange = [[httpResponse allHeaderFields] objectForKey:@"Content-Range"];
    NSString * fileLength = [[contentRange componentsSeparatedByString:@"/"] lastObject];
    self.fileLen = fileLength.longLongValue > 0 ? fileLength.longLongValue : response.expectedContentLength;
    
    self.MimeType = mimeType;
    if (!self.response) {
        NSLog(@"response = %@",response);
    }
    self.response = response;
    [self fillContentInformationRequest];//填充信息
    
    //该函数方法必须最后调用
    completionHandler(NSURLSessionResponseAllow);
}

- (void)fillContentInformationRequest {
    AVAssetResourceLoadingContentInformationRequest *contentInformationRequest = self.loadingRequest.contentInformationRequest;
    CFStringRef contentType = UTTypeCreatePreferredIdentifierForTag(kUTTagClassMIMEType, (__bridge CFStringRef)(self.MimeType), NULL);
    contentInformationRequest.contentType = CFBridgingRelease(contentType);
    contentInformationRequest.contentLength = self.fileLen;
    contentInformationRequest.byteRangeAccessSupported = YES;
}

//开始接收数据
- (void)URLSession:(NSURLSession *)session
          dataTask:(NSURLSessionDataTask *)dataTask
    didReceiveData:(NSData *)data {
    [self.mediaData appendData:data];
    [self.loadingRequest.dataRequest respondWithData:data];
    NSLog(@"didReceiveData --------------- dataLen = %lu",self.mediaData.length);
}

//错误处理
- (void)URLSession:(NSURLSession *)session
              task:(NSURLSessionTask *)task
didCompleteWithError:(NSError *)error {
    if (error.code == NSURLErrorCancelled) {
        return;
    }
    
    if (!error) {
        [self.loadingRequest finishLoading];
    } else {
        [self.loadingRequest finishLoadingWithError:error];
    }
}

- (NSError *)loaderCancelledError{
    NSError *error = [[NSError alloc] initWithDomain:@"com.resourceloader"
                                                code:-3
                                            userInfo:@{NSLocalizedDescriptionKey:@"Resource loader cancelled"}];
    return error;
}

@end
